package com.br.aiops.rule;

import com.br.aiops.receiver.AlertLog;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.googlecode.aviator.Expression;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * 该类主要用于匹配日志规则
 */
@Component
public class RulePattern {

    private static final Logger LOGGER = LoggerFactory.getLogger(RulePattern.class);

    @Autowired
    private RuleCache ruleCache;


    /**
     * 根据告警日志对象匹配对应的规则，如果匹配则返回；否则返回null
     * @param alertLog 日志对象
     * @return 如果匹配则返回rule；否则返回null
     */
    public List<Rule> patten(AlertLog alertLog) {
        //过滤该service、errorCode，并且match表达式的rule
        return ruleCache.getRules().stream()
                .filter(rule -> matchEnv(alertLog, rule))
                .filter(rule -> Objects.equals(rule.getService(), alertLog.getService()))
                .filter(rule -> Objects.equals(rule.getErrorCode(), alertLog.getErrorCode()))
                .filter(rule -> match(rule, alertLog))
                .collect(Collectors.toList());
    }

    /**
     * 是否匹配子环境subenv
     * 如果客户端配置了subenv，则获取对应子环境的rule；如果没有配置subenv，则获取没有配置子环境的rule
     * @param alertLog
     * @param rule
     * @return
     */
    private boolean matchEnv(AlertLog alertLog, Rule rule) {
        if (StringUtils.isNotBlank(alertLog.getSubEnv())) {
            return Objects.equals(alertLog.getSubEnv(), rule.getSubEnv());
        }
        return StringUtils.isBlank(rule.getSubEnv());
    }

    /**
     * 是否匹配正则表达式或规则
     * @param rule
     * @param alertLog
     * @return
     */
    private boolean match(Rule rule, AlertLog alertLog) {
        Matcher matcher = rule.getPattern().matcher(alertLog.getAlertName());
        //如果正则表达式为空或者为*（全部匹配），则直接返回true
        if (StringUtils.isBlank(rule.getRegex()) || "*".equals(rule.getRegex().trim())) {
            return true;
        } else if (StringUtils.isBlank(rule.getExpr())) {
            return matcher.matches();
        } else {
            return matchExpr(matcher, alertLog.getAlertName(), rule);
        }
    }

    /**
     * 匹配expr
     * @param matcher
     * @return
     */
    private boolean matchExpr(Matcher matcher, String str, Rule rule) {
        if (matcher.find()) {
            List<Double> values = Lists.newArrayList();
            int groupCount = matcher.groupCount();
            try {
                for (int i = 1; i <= groupCount; i ++) {
                    values.add(Double.valueOf(matcher.group(i)));
                }
            } catch (Exception e) {
                LOGGER.error("提取时正则的group时，parseDouble异常。", e);
                return false;
            }
            return execute(values, rule.getExpression());
        }
        return false;
    }

    /**
     * 根据group values和表达式对象，执行表达式返回值
     * @param groupValues
     * @param expression
     * @return
     */
    public boolean execute(List<Double> groupValues, Expression expression) {

        Map<String, Object> env = Maps.newHashMapWithExpectedSize(8);
        for (int i = 0; i < groupValues.size(); i ++) {
            env.put("$" + (i + 1), groupValues.get(i));
        }

        return (Boolean) expression.execute(env);
    }
}
